package org.quipu.client;

import com.google.gwt.dom.client.SelectElement;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Widget;
import java.util.LinkedList;
import java.util.List;
import org.quipu.client.events.AppEvent;
import org.quipu.client.events.AppEventBus;
import org.quipu.client.events.AppEventListener;
import org.quipu.client.events.BaseSelectionChangedEvent;
import org.quipu.client.events.ErrorEvent;

public abstract class AppListBox extends AppEventWidget implements AppEventListener {

    private ListBox listBox;
    private Long selectedId;
    private final Class eventClass;
    private final BaseSelectionChangedEvent selectionChangedEvent;
    private final List<ControlChangeHandler<? extends AppListBox, Long>> changeHandlers;

    public AppListBox(AppEventBus eventBus, AppCache cache, Class eventClass, BaseSelectionChangedEvent selectionChangedEvent, Long selectedId) {
        super(eventBus, cache);
        this.eventClass = eventClass;
        this.selectionChangedEvent = selectionChangedEvent;
        changeHandlers = new LinkedList<ControlChangeHandler<? extends AppListBox, Long>>();
        listBox = new ListBox(false);
        listBox.addChangeHandler(new ChangeHandler() {

            public void onChange(ChangeEvent event) {
                disableHeadItem();
                int selectedIndex = listBox.getSelectedIndex();
                if(selectedIndex >= 0) {
                    String selectedIdValue = listBox.getValue(selectedIndex);
                    try {
                        setSelectedId(Long.valueOf(selectedIdValue));
                        if(AppListBox.this.selectionChangedEvent != null) {
                            try {
                                AppListBox.this.selectionChangedEvent.setOriginator(AppListBox.this);
                                AppListBox.this.selectionChangedEvent.setObject(getSelectedId());
                                getEventBus().fireEvent(AppListBox.this.selectionChangedEvent);
                            } catch(Exception ex) {
                                getEventBus().fireEvent(new ErrorEvent(AppListBox.this, ex.getMessage()));
                            }
                        }
                        for(ControlChangeHandler changeHandler: changeHandlers) {
                            changeHandler.onChange(AppListBox.this, new Long[] {Long.valueOf(selectedIdValue)});
                        }
                    } catch(NumberFormatException ex) {
                        setSelectedId(null);
                    }
                }
            }
        });
    }

    @Override
    public final void init() {
        getEventBus().addListener(eventClass, this);
    }

    @Override
    public final void handleEvent(AppEvent event) {
        refresh();
    }

    @Override
    public Widget getWidget() {
        return listBox;
    }

    protected ListBox getListBox() {
        return listBox;
    }

    protected Long getSelectedId() {
        return selectedId;
    }

    protected void setSelectedId(Long selectedId) {
        this.selectedId = selectedId;
    }

    public void selectValue(Long selectedId) {
        setSelectedId(selectedId);
        refresh();
    }

    private void disableHeadItem() {
        SelectElement selectElement = listBox.getElement().cast();
        selectElement.getOptions().getItem(0).setDisabled(true);
    }

    public Long getValue() {
        return getSelectedId();
    }

    public void addChangeHandler(ControlChangeHandler<? extends AppListBox, Long> changeHandler) {
        changeHandlers.add(changeHandler);
    }

    protected abstract void refresh();
}
